package kuzha.code.jvm;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;

import org.objectweb.asm.Label;

class BlockManager {
	private final Deque<Block> blocks = new LinkedList<Block>();
	
	public void pushBlock(String name, Label _break, Label _continue) {
		pushBlock(name, false, _break, _continue, null);
	}
	public void pushStrongBlock(String name, Label _break, Label _continue) {
		pushBlock(name, true, _break, _continue, null);
	}
	public void pushFinally(CodeEmitter _finally) {
		pushBlock(null, false, null, null, _finally);
	}
	private void pushBlock(String name, boolean standard, Label _break, Label _continue, CodeEmitter _finally) {
		blocks.addFirst(new Block(name, standard, _break, _continue, _finally));
	}
	public void popBlock() {
		blocks.removeFirst();
	}
	
	private Block getBlock(String name) {
		for(Block block: blocks) {
			if (name == null ? block.standard : name.equals(block.name)) {
				return block;
			}
		}
		return null;
	}
	
	public Label getBreak(String name) {
		Block block = getBlock(name);
		return block == null ? null : block._break;
	}
	public Label getContinue(String name) {
		Block block = getBlock(name);
		return block == null ? null : block._continue;
	}
	
	public CodeEmitter[] getFinally(String name) {
		List<CodeEmitter> result = new ArrayList<CodeEmitter>();
		for(Block block: blocks) {
			if (block._finally != null) {
				result.add(block._finally);
			}
			if (name == null ? block.standard : name.equals(block.name)) {
				break;
			}
		}
		return result.toArray(new CodeEmitter[result.size()]);
	}
	public CodeEmitter[] getAllFinally() {
		List<CodeEmitter> result = new ArrayList<CodeEmitter>();
		for(Block block: blocks) {
			if (block._finally != null) {
				result.add(block._finally);
			}
		}
		return result.toArray(new CodeEmitter[result.size()]);
	}
	
	private static class Block {
		public final String name; 
		public final boolean standard;
		public final Label _break, _continue;
		public final CodeEmitter _finally;
		
		public Block(String name, boolean standard, Label _break, Label _continue, CodeEmitter _finally) {
			super();
			this.name = name;
			this.standard = standard;
			this._break = _break;
			this._continue = _continue;
			this._finally = _finally;
		}
	}
}
